﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using StoreHoursDomain.Entity;
using Domain.Provider;
using System.Diagnostics;

namespace StoreHoursDomain.Provider
{
    public class StoreProvider : IDataProvider<Store>
    {
        private DatabaseProvider databaseProvider = new DatabaseProvider();

        public IEnumerable<Store> Entities
        {
            get
            {
                var entities = new List<Store>();
                var storeHours = ((IDataProvider<Domain.Context.StoreHours>)databaseProvider).Entities;
                var weeklyStoreHoursCache = WeeklyStoreHours.ToList();
                var storeIds = weeklyStoreHoursCache.GroupBy(h => h.storeId).Select(h => h.First().storeId);
               
                foreach (var id in storeIds)
                {
                    entities.Add(new Store { ID = id, Name = "" + id, AllHours = weeklyStoreHoursCache.Where(hours => hours.storeId == id).ToList() });
                }

                return entities;
            }
        }

        public void SaveEntity(Store entity, IPrincipal user)
        {
           
        }

        public void DeleteEntity(Store entity, IPrincipal user)
        {
            throw new NotSupportedException();
        }

        private Domain.Context.StoreHours GetStoreHours(IEnumerable<Domain.Context.StoreHours> storeHours, int storeId, int dow, DateTime latestTime)
        {
            return storeHours.Where(h => h.StoreID == storeId && h.DOW == dow && h.StartAfter <= latestTime).OrderBy(h => h.StartAfter).FirstOrDefault();
        }
        private StoreHours DatabaseStoreHoursToDomainStoreHours(Domain.Context.StoreHours hours)
        {
            return hours == null || string.IsNullOrEmpty(hours.TimeOpen) || string.IsNullOrEmpty(hours.TimeClosed) ?
                new StoreHours { Closed = true, StartTime = DateTime.Now, EndTime = DateTime.Now } :
                new StoreHours { StartTime = DateTime.Parse(hours.TimeOpen), EndTime = DateTime.Parse(hours.TimeClosed) };
        }
        //THIS CODE IS HIGHLY UN-OPTIMIZED, TRY TO DEBUG THE UNCOMMENTED CODE AND USE THAT
        IEnumerable<WeeklyStoreHours> WeeklyStoreHours
        {
            get
            {
                const int mondayIndex = 0;
                const int sundayIndex = 6;
                var returnWeeklyStoreHours = new List<WeeklyStoreHours>();
                /*var storeHours = ((IDataProvider<Domain.Context.StoreHours>) databaseProvider).Entities.ToList();
                var storeHoursBin = storeHours.ToList();

                while (storeHoursBin.Count > 0)
                {
                    var weeklyStoreHours = new WeeklyStoreHours { EffectiveDate = storeHoursBin[0].StartAfter, storeId = storeHoursBin[0].StoreID };

                    weeklyStoreHours.SetHours((DayOfWeek)storeHoursBin[0].DOW, DatabaseStoreHoursToDomainStoreHours(storeHoursBin[0]));

                    storeHoursBin.RemoveAt(0);

                    for (int i = mondayIndex; i <= sundayIndex; i++)
                    {
                        var hours = GetStoreHours(storeHours, weeklyStoreHours.storeId, i, weeklyStoreHours.EffectiveDate);

                        if (hours != null)
                        {
                            weeklyStoreHours.SetHours((DayOfWeek)i, DatabaseStoreHoursToDomainStoreHours(hours));

                            storeHoursBin.Remove(hours);
                        }
                        else
                        {
                            weeklyStoreHours.SetHours((DayOfWeek)i, new StoreHours { Closed = true });
                        }
                    }

                    returnWeeklyStoreHours.Add(weeklyStoreHours);
                }*/

                var watch = Stopwatch.StartNew();
                var allWeeklyStoreHours = ((IDataProvider<Domain.Context.StoreHours>)databaseProvider).Entities.ToList();
                
                foreach (var weeklyStoreHours in allWeeklyStoreHours)
                {
                    WeeklyStoreHours convertedHours;

                    if (!returnWeeklyStoreHours.Any(hours => hours.EffectiveDate == weeklyStoreHours.StartAfter && hours.storeId == weeklyStoreHours.StoreID))
                    {
                        //convertedHours = returnWeeklyStoreHours.First(hours => hours.EffectiveDate == weeklyStoreHours.StartAfter && hours.storeId == weeklyStoreHours.StoreID);

                        convertedHours = new WeeklyStoreHours { EffectiveDate = weeklyStoreHours.StartAfter, storeId = weeklyStoreHours.StoreID };

                        //convertedHours.SetHours((DayOfWeek)weeklyStoreHours.DOW, DatabaseStoreHoursToDomainStoreHours(GetStoreHours(allWeeklyStoreHours, convertedHours.storeId, weeklyStoreHours.DOW, convertedHours.EffectiveDate)));

                        convertedHours.MondayHours = DatabaseStoreHoursToDomainStoreHours(GetStoreHours(allWeeklyStoreHours, convertedHours.storeId, 0, convertedHours.EffectiveDate));
                        convertedHours.TuesdayHours = DatabaseStoreHoursToDomainStoreHours(GetStoreHours(allWeeklyStoreHours, convertedHours.storeId, 1, convertedHours.EffectiveDate));
                        convertedHours.WednesdayHours = DatabaseStoreHoursToDomainStoreHours(GetStoreHours(allWeeklyStoreHours, convertedHours.storeId, 2, convertedHours.EffectiveDate));
                        convertedHours.ThursdayHours = DatabaseStoreHoursToDomainStoreHours(GetStoreHours(allWeeklyStoreHours, convertedHours.storeId, 3, convertedHours.EffectiveDate));
                        convertedHours.FridayHours = DatabaseStoreHoursToDomainStoreHours(GetStoreHours(allWeeklyStoreHours, convertedHours.storeId, 4, convertedHours.EffectiveDate));
                        convertedHours.SaturdayHours = DatabaseStoreHoursToDomainStoreHours(GetStoreHours(allWeeklyStoreHours, convertedHours.storeId, 5, convertedHours.EffectiveDate));
                        convertedHours.SundayHours = DatabaseStoreHoursToDomainStoreHours(GetStoreHours(allWeeklyStoreHours, convertedHours.storeId, 6, convertedHours.EffectiveDate));

                        returnWeeklyStoreHours.Add(convertedHours);
                    }
                }

                Debug.WriteLine("Time taken: " + watch.ElapsedMilliseconds);

                return returnWeeklyStoreHours;
            }
        }
    }
}
